package no.group.gowther.exception;

import no.group.gowther.GowtherApplication;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import no.group.gowther.rest.vo.Result;

/**
 * @author ayatsuji
 * @date 2022-03-05 22:04
 * @since
 */
@RestControllerAdvice(basePackageClasses = GowtherApplication.class)
public class GlobalExceptionHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(BusinessException.class)
    public Result<?> handle(BusinessException e) {
        return Result.failure(e.getCode(), e.getErrorMsg());
    }

    @ExceptionHandler(Exception.class)
    public Result<?> defaultHandle(Exception e, HttpServletRequest request) {
        LOGGER.error("系统内部出错, 请求url=[{}], 请求参数[header=[{}], param={}]",
                request.getRequestURI(),
                getHeaderMap(request),
                getParamMap(request),
                e);
        return Result.failure(ErrorMessage.SYSTEM_ERROR.getErrorCode(),
                              ErrorMessage.SYSTEM_ERROR.getErrorMsg());
    }

    /**
     * 参数校验
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public Result<?> handle(MethodArgumentTypeMismatchException e) {
        return Result.failure(ErrorMessage.PARAM_ERROR.getErrorCode(), "参数" + e.getName() + "类型错误");
    }

    /**
     * 参数校验
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public Result<?> handle2(ConstraintViolationException e) {
        StringBuilder builder = new StringBuilder();
        for (ConstraintViolation<?> v: e.getConstraintViolations()) {
            String paramName = ((PathImpl) v.getPropertyPath()).getLeafNode().asString();
            builder.append(paramName)
                    .append(v.getMessage())
                    .append(", 当前传值为[")
                    .append(v.getInvalidValue())
                    .append("]; ");
        }
        return Result.failure(ErrorMessage.PARAM_ERROR.getErrorCode(), builder.toString());
    }

    /**
     * 参数校验
     */
    @ExceptionHandler(BindException.class)
    public Result<?> handle3(BindException e) {
        final String defaultMessage = e.getAllErrors().get(0).getDefaultMessage();
        return Result.failure(ErrorMessage.PARAM_ERROR.getErrorCode(), defaultMessage);
    }

    private Map<String, String> getHeaderMap(HttpServletRequest request) {
        Map<String, String> headerMap = new HashMap<>();
        final Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            final String headerName = headerNames.nextElement();
            headerMap.put(headerName, request.getHeader(headerName));
        }
        return headerMap;
    }

    private Map<String, String> getParamMap(HttpServletRequest request) {
        return request.getParameterMap().entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, entry -> Arrays.toString(entry.getValue())));
    }

}
